/* -*- c++ -*- */
/*
 * This file is part of the SD Project.
 *
 * Authors: Cleiber Marques da Silva <cleiber@lisha.ufsc.br>
 * 			Odilson Tadeu Valle <odilson@sj.ifsc.edu.br>
 * 
 * SD Project is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; version 2 of the License.
 */

#include <iostream>
#include <fstream>
#include <cstdlib>

#include "config.h"

namespace sd {
	config::config(std::string file)
	{
		char buffer[1024];
		group_stack.push_front(this);
		std::ifstream in(file.c_str());

		while(in) {
			in.getline(buffer, 1024);
			std::string line = buffer;
			if ((line.length() > 2) && (line[0] != '#') && (line.find(')') == std::string::npos)) {
				std::string name;
				std::string value;
				split(line, name, value, '=');

				// new group
				if (value == "(") {
					sd::config *new_group = new sd::config();
					group_stack.front()->groups[name] = new_group;
					group_stack.push_front(new_group);
				} else {
					for (std::list<sd::config*>::reverse_iterator i = group_stack.rbegin(); i != group_stack.rend(); i++)
						(*i)->symbol_expand(value);

					env_symbol_expand(value);
					group_stack.front()->add(name, value);
				}
			}

			if ( (line.length() > 0) && (line[0] != '#') && (line.find(')') != std::string::npos) ) 
				group_stack.pop_front();
		
		}
		in.close();
	}

	void config::split(std::string in, std::string& left, std::string& right, char c)
	{
		size_t pos = in.find_first_of(c);
		if(pos == std::string::npos) {
			left = in;
			trim(left);
			right = "";
		} else if (pos <= 1) {
			left = "";
			right = in.substr(pos+1, std::string::npos);
			trim(right);
		} else {
			left = in.substr(0, pos-1);
			trim(left);
			right = in.substr(pos+1, std::string::npos);
			trim(right);
		}
	}	

	void config::trim(std::string& s)
	{
		while ( (s.length() > 1) && ( (s[0] == ' ') || (s[0] =='\t') ) ) {
			s = s.substr(1, std::string::npos);
		}
		while ( (s.length() > 1) &&
			( (s[s.length()-1] == ' ') ||
			  (s[s.length()-1] == '\t') || 
			  (s[s.length()-1] == '\n') || 
			  (s[s.length()-1] == '\r') ) ) {
				s = s.substr(0, s.length()-1);
		}		
		if ( (s.length() > 1) && (s[0] == '"') ) {
			s = s.substr(1, std::string::npos);
		}
		if ( (s.length() > 1) && (s[s.length()-1] == '"') ) {
			s = s.substr(0, s.length()-1);
		}
	}

	void config::symbol_expand(std::string& s)
	{
		symbol_expand(symbols, s);
	}

	void config::symbol_expand(std::map<std::string, std::string>& symbols, std::string& s)
	{
		bool expanded;
		do {
			expanded = false;
			for (std::map<std::string, std::string>::iterator i = symbols.begin(); i != symbols.end(); ++i) {
				std::string search = "%" + i->first + "%";
				std::string replace = i->second;
				size_t pos = s.find(search);
				if (pos != std::string::npos) {
					expanded = true;
					s.replace(pos, search.length(), replace);
				}	
			}
		} while (expanded);
	}

	void config::env_symbol_expand(std::string& s)
	{
		symbol_expand(env_symbols, s);
	}

	void config::add(std::string name, std::string value) {
		symbols[name] = value;
	}

	std::string config::type_string(std::string name)
	{
		std::map<std::string, std::string>::iterator i = symbols.find(name);
		return i->second;
	}

	int config::type_int(std::string name)
	{
		std::string val = type_string(name);
		return atoi(val.c_str());
	}
}
